package main

import (
	"database/sql"
	"encoding/json"
	"io"
	"log"
	"net"
	"net/http"
	"time"

	"github.com/go-sql-driver/mysql" // 导入mysql驱动包
	_ "github.com/go-sql-driver/mysql"
	"github.com/gorilla/mux"
	"github.com/gorilla/websocket"
)

type TowerCraneData struct {
	TowerCraneData1
	TowerCraneData2
	TowerCraneData3
	TowerCraneData4
	TowerCraneData5
}

// TowerCraneData1 定义塔吊数据结构
type TowerCraneData1 struct {
	ManufacturerID  uint32         `json:"manufacturerID"`  // 厂家编号
	ProtocolVersion uint32         `json:"protocolVersion"` // 协议版本
	DeviceType      uint32         `json:"deviceType"`      // 设备类型
	Timestamp       mysql.NullTime `json:"timestamp"`       // 时间戳
}

// TowerCraneData2 设备属性信息上传
type TowerCraneData2 struct {
	SIMCardNumber      string  `json:"sIMCardNumber"`      // SIM卡号
	GroupTowerID       uint16  `json:"groupTowerID"`       // 群塔ID
	TowerInGroupID     uint16  `json:"towerInGroupID"`     // 塔机在群ID
	RopeMultiplier     uint8   `json:"ropeMultiplier"`     // 吊绳倍率
	TowerCoordinatesX  float64 `json:"towerCoordinatesX"`  // 塔机X坐标
	TowerCoordinatesY  float64 `json:"towerCoordinatesY"`  // 塔机Y坐标
	ArmLength1         float64 `json:"armLength1"`         // 臂长度1
	ArmLength2         float64 `json:"armLength2"`         // 臂长度2
	TowerHeight        float64 `json:"towerHeight"`        // 塔帽长度
	TowerHeightAbove   float64 `json:"towerHeightAbove"`   // 塔身高度
	Longtitude         float64 `json:"longtitude"`         // 经度
	Latitude           float64 `json:"latitude"`           // 纬度
	TurnMaxLeft        float64 `json:"turnMaxLeft"`        // 左转最大幅度
	TurnMaxRight       float64 `json:"turnMaxRight"`       // 右转最大幅度
	TrolleyFrontLimit  float64 `json:"rolleytFrontLimit"`  // 小车前极限
	TrolleyBackLimit   float64 `json:"trolleyBackLimit"`   // 小车后极限
	HoistingHeight     float64 `json:"hoistingHeight"`     // 起升高度
	MaxLiftingCapacity float64 `json:"maxLiftingCapacity"` // 最大起重量
	MaxWeight          float64 `json:"maxWeight"`          // 最大重量
	TorqueWarningPct   uint8   `json:"torqueWarningPct"`   // 力矩预警百分比
	AlertPct           uint8   `json:"alertPct"`           // 报警百分比
	ViolationPct       uint8   `json:"violationPct"`       // 违章百分比
}

// TowerCraneData3 设备实时数据上传
type TowerCraneData3 struct {
	Timestamp         mysql.NullTime `json:"timestamp"`         // 时间戳
	Height            float64        `json:"height"`            // 高度
	Radius            float64        `json:"radius"`            // 半径
	Rotation          float64        `json:"rotation"`          // 旋转
	Weight            float64        `json:"weight"`            // 重量
	SafeWeight        float64        `json:"safeWeight"`        // 安全重量
	SafeWeightPercent uint8          `json:"safeWeightPercent"` // 安全重量百分比
	Moment            float64        `json:"moment"`            // 力矩
	MomentLoadPercent uint8          `json:"momentLoadPercent"` // 力矩负载百分比
	WindSpeed         float64        `json:"windSpeed"`         // 风速
	TiltX             float64        `json:"tiltX"`             // X轴倾斜
	TiltY             float64        `json:"tiltY"`             // Y轴倾斜
	DeviceStatus      float64        `json:"deviceStatus"`      // 设备状态
	Depth             float64        `json:"depth"`             // 深度
	Checksum          uint8          `json:"checksum"`          // 校验和
}

// TowerCraneData4 定义塔吊数据结构
type TowerCraneData4 struct {
	Timestamp           mysql.NullTime `json:"timestamp"`           // 时间戳
	StartTime           mysql.NullTime `json:"startTime"`           // 开始时间
	EndTime             mysql.NullTime `json:"endTime"`             // 结束时间
	MaxTload            float64        `json:"maxTload"`            // 最大载荷
	LoadPercentage      uint8          `json:"loadPercentage"`      // 载荷百分比
	MaxTorque           float64        `json:"maxTorque"`           // 最大力矩
	TorquePercentage    uint8          `json:"torquePercentage"`    // 力矩百分比
	Sangle              float64        `json:"sangle"`              // 起始角度
	Eangle              float64        `json:"eangle"`              // 结束角度
	SswingAngle         float64        `json:"sswingAngle"`         // 起始摆动角度
	EswingAngle         float64        `json:"eswingAngle"`         // 结束摆动角度
	MaxSwingAngle       float64        `json:"maxSwingAngle"`       // 最大摆动角度
	MinSwingAngle       float64        `json:"minSwingAngle"`       // 最小摆动角度
	Startheight         float64        `json:"startheight"`         // 开始高度
	Endheight           float64        `json:"endheight"`           // 结束高度
	MaxLiftHeight       float64        `json:"maxLiftHeight"`       // 最大起升高度
	MinLiftHeight       float64        `json:"minLiftHeight"`       // 最小起升高度
	MaxWorkingWindSpeed float64        `json:"maxWorkingWindSpeed"` // 最大工作风速
	MaxTiltAngleX       float64        `json:"maxTiltAngleX"`       // X轴最大倾角
	MaxTiltAngleY       float64        `json:"maxTiltAngleY"`       // Y轴最大倾角
	DeviceStatus        uint32         `json:"deviceStatus"`        // 设备状态
}

// TowerCraneData5 定义塔吊数据结构
type TowerCraneData5 struct {
	Timestamp    mysql.NullTime `json:"timestamp"`    // 时间戳
	Driver_state uint8          `json:"driver_state"` // 司机状态
	Driver_id    string         `json:"driver_id"`    // 司机ID
}

// 用于TCP服务器和WebSocket服务之间通信的通道
var tcpToWsMessageChannel = make(chan string)
var latestCraneData TowerCraneData

// upgrader 用于升级HTTP连接为WebSocket连接
var upgrader = websocket.Upgrader{
	ReadBufferSize:  1024,
	WriteBufferSize: 1024,
	CheckOrigin: func(r *http.Request) bool {
		return true
	},
}

// updateSignal 用于触发WebSocket数据更新
var updateSignal = make(chan struct{}, 1)

func handleTCPConnection(conn net.Conn) {
	defer conn.Close()

	for {
		buffer := make([]byte, 1024)
		bytesRead, err := conn.Read(buffer)
		if err != nil {
			if err != io.EOF {
				log.Println("Error reading from connection:", err)
			}
			break
		}
		// 当接收到TCP消息时，发送到通道
		tcpToWsMessageChannel <- string(buffer[:bytesRead])
	}
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
	// 使用gorilla WebSocket升级HTTP连接
	conn, err := upgrader.Upgrade(w, r, nil)
	if err != nil {
		log.Println("Error upgrading connection:", err)
		return
	}
	defer conn.Close()

	// 创建一个用于控制退出循环的通道
	exit := make(chan struct{})

	// 启动一个goroutine来处理Ping/Pong消息，保持连接活跃
	go func() {
		ticker := time.NewTicker(3 * time.Second)
		defer ticker.Stop()
		for {
			select {
			case <-ticker.C:
				// 定时发送Pong消息
				if err := conn.WriteControl(websocket.PongMessage, nil, time.Now().Add(time.Second)); err != nil {
					log.Println("Failed to write Pong frame:", err)
					close(exit)
					return
				}
			case <-exit:
				// 退出goroutine
				return
			}
		}
	}()

	// 主循环处理WebSocket消息
	for {
		// 根据实际业务逻辑处理接收到的消息
		// 例如，使用conn.ReadMessage()来接收消息

		// 模拟数据更新信号
		select {
		case <-updateSignal:
			// 从数据库获取数据的逻辑
			var data TowerCraneData
			if err := fetchDataFromDB(&data); err != nil {
				log.Println("Failed to fetch data from DB:", err)
				if err := conn.WriteMessage(websocket.TextMessage, []byte("Error fetching data")); err != nil {
					log.Println("Failed to write message to WebSocket:", err)
				}
				continue
			}

			// 序列化数据并发送的逻辑
			jsonData, err := json.Marshal(data)
			if err != nil {
				log.Println("Failed to marshal JSON:", err)
				if err := conn.WriteMessage(websocket.TextMessage, []byte("Error marshalling JSON")); err != nil {
					log.Println("Failed to write message to WebSocket:", err)
				}
				continue
			}

			if err := conn.WriteMessage(websocket.TextMessage, jsonData); err != nil {
				log.Println("Failed to write message to WebSocket:", err)
				// 如果写入失败，可能是由于连接关闭或其他网络问题
				close(exit)
				return
			}
		}
	}
	for {
		// 选择接收来自通道的消息或处理WebSocket消息
		select {
		case message := <-tcpToWsMessageChannel:
			// 收到TCP服务器的消息，通过WebSocket发送给客户端
			if err := conn.WriteMessage(websocket.TextMessage, []byte(message)); err != nil {
				log.Println("Failed to write message to WebSocket:", err)
				return
			}
			// 处理WebSocket消息的case
			// ...
		}
	}

	// 清理和退出
	close(exit)
}

// ... 处理接收到的消息 ...

func fetchDataFromDB(data *TowerCraneData) error {
	// 数据库连接字符串
	dsn := "root:770525@/tower_crane_db"
	db, err := sql.Open("mysql", dsn)
	if err != nil {
		return err
	}
	defer db.Close()

	if err := db.Ping(); err != nil {
		return err
	}

	// 从数据库查询最新的塔吊数据
	err = db.QueryRow("SELECT manufacturerID, protocolversion, deviceType, timestamp FROM crane_data1 ORDER BY id DESC LIMIT 1").Scan(
		&data.TowerCraneData1.ManufacturerID,
		&data.TowerCraneData1.ProtocolVersion,
		&data.TowerCraneData1.DeviceType,
		&data.TowerCraneData1.Timestamp,
	)
	if err != nil {
		return err
	}
	err = db.QueryRow("SELECT sIMCardNumber, groupTowerID, towerInGroupID, ropeMultiplier, towerCoordinatesX, towerCoordinatesY, armlength1, armlength2, towerHeight, towerHeightAbove, longtitude, latitude, turnMaxLeft, turnMaxRight, trolleyFrontLimit, trolleyBackLimit, hoistingHeight, maxLiftingCapacity, maxWeight, torqueWarningPct, alertPct, violationPct FROM crane_data2 ORDER BY id DESC LIMIT 1").Scan(
		&data.TowerCraneData2.SIMCardNumber,
		&data.TowerCraneData2.GroupTowerID,
		&data.TowerCraneData2.TowerInGroupID,
		&data.TowerCraneData2.RopeMultiplier,
		&data.TowerCraneData2.TowerCoordinatesX,
		&data.TowerCraneData2.TowerCoordinatesY,
		&data.TowerCraneData2.ArmLength1,
		&data.TowerCraneData2.ArmLength2,
		&data.TowerCraneData2.TowerHeight,
		&data.TowerCraneData2.TowerHeightAbove,
		&data.TowerCraneData2.Longtitude,
		&data.TowerCraneData2.Latitude,
		&data.TowerCraneData2.TurnMaxLeft,
		&data.TowerCraneData2.TurnMaxRight,
		&data.TowerCraneData2.TrolleyFrontLimit,
		&data.TowerCraneData2.TrolleyBackLimit,
		&data.TowerCraneData2.HoistingHeight,
		&data.TowerCraneData2.MaxLiftingCapacity,
		&data.TowerCraneData2.MaxWeight,
		&data.TowerCraneData2.TorqueWarningPct,
		&data.TowerCraneData2.AlertPct,
		&data.TowerCraneData2.ViolationPct,
	)
	if err != nil {
		return err
	}
	err = db.QueryRow("SELECT `timestamp`, height, radius, rotation, weight, safe_weight, safe_weight_percent, moment, moment_load_percent, wind_speed, tilt_x, tilt_y, device_status, depth, checksum FROM crane_data3 ORDER BY id DESC LIMIT 1").Scan(
		&data.TowerCraneData3.Timestamp,
		&data.TowerCraneData3.Height,
		&data.TowerCraneData3.Radius,
		&data.TowerCraneData3.Rotation,
		&data.TowerCraneData3.Weight,
		&data.TowerCraneData3.SafeWeight,
		&data.TowerCraneData3.SafeWeightPercent,
		&data.TowerCraneData3.Moment,
		&data.TowerCraneData3.MomentLoadPercent,
		&data.TowerCraneData3.WindSpeed,
		&data.TowerCraneData3.TiltX,
		&data.TowerCraneData3.TiltY,
		&data.TowerCraneData3.DeviceStatus,
		&data.TowerCraneData3.Depth,
		&data.TowerCraneData3.Checksum,
	)
	if err != nil {
		return err
	}
	err = db.QueryRow("SELECT `timestamp`, startTime, endTime, maxTload, loadPercentage, maxTorque, torquePercentage, sangle, eangle, sswingAngle, eswingAngle, maxSwingAngle, minSwingAngle, startheight, endheight, maxLiftHeight, minLiftHeight, maxWorkingWindSpeed, maxTiltAngleX, maxTiltAngleY, deviceStatus FROM crane_data4 ORDER BY id DESC LIMIT 1").Scan(
		&data.TowerCraneData4.Timestamp,
		&data.TowerCraneData4.StartTime,
		&data.TowerCraneData4.EndTime,
		&data.TowerCraneData4.MaxTload,
		&data.TowerCraneData4.LoadPercentage,
		&data.TowerCraneData4.MaxTorque,
		&data.TowerCraneData4.TorquePercentage,
		&data.TowerCraneData4.Sangle,
		&data.TowerCraneData4.Eangle,
		&data.TowerCraneData4.SswingAngle,
		&data.TowerCraneData4.EswingAngle,
		&data.TowerCraneData4.MaxSwingAngle,
		&data.TowerCraneData4.MinSwingAngle,
		&data.TowerCraneData4.Startheight,
		&data.TowerCraneData4.Endheight,
		&data.TowerCraneData4.MaxLiftHeight,
		&data.TowerCraneData4.MinLiftHeight,
		&data.TowerCraneData4.MaxWorkingWindSpeed,
		&data.TowerCraneData4.MaxTiltAngleX,
		&data.TowerCraneData4.MaxTiltAngleY,
		&data.TowerCraneData4.DeviceStatus,
	)
	if err != nil {
		return err
	}
	err = db.QueryRow("SELECT `timestamp`, driver_state, driver_id FROM crane_data5 ORDER BY id DESC LIMIT 1").Scan(
		&data.TowerCraneData5.Timestamp,
		&data.TowerCraneData5.Driver_state,
		&data.TowerCraneData5.Driver_id,
	)
	if err != nil {
		return err
	}

	return nil
}

// main 函数启动Web服务
func main() {
	r := mux.NewRouter()
	r.HandleFunc("/ws", handleWebSocket)
	// 启动WebSocket服务
	go func() {
		log.Println("Starting server on :8085")
		if err := http.ListenAndServe(":8085", r); err != nil {
			log.Fatal("ListenAndServe: ", err)
		}
	}()

	// 模拟周期性更新
	go func() {
		for {
			// 这里可以添加实际的更新逻辑
			// 例如，从传感器获取数据更新craneData

			// 触发WebSocket数据更新
			updateSignal <- struct{}{}

			// 模拟5秒更新一次
			time.Sleep(5 * time.Second)
		}
	}()

	// 阻塞主线程，直到程序退出
	select {}
}
